/**    
 * 文件名：ChangeRoomService.java</br>
 *    
 * 版本信息：v1.0</br>
 * 日期：2017年12月13日</br>
 * © 2005-2017 雷技信息科技（上海）有限公司版权所有</br>
 *
 */
package com.logic.landseaserver.models.changeroom.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.logic.landseaserver.domain.*;
import com.logic.landseaserver.persistence.read.*;
import com.logic.landseaserver.persistence.write.*;
import com.logic.landseaserver.service.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.google.gson.Gson;
import com.logic.common.exception.BusinessException;
import com.logic.common.security.SecurityUtils;
import com.logic.landseaserver.common.LandeaConstants;
import com.logic.landseaserver.common.LandeaConstants.AccountStatus;
import com.logic.landseaserver.common.LandeaConstants.ChangeRoomStatus;
import com.logic.landseaserver.common.LandeaConstants.ReRentType;
import com.logic.landseaserver.common.LandseaErrorMessageEnum;
import com.logic.landseaserver.common.enums.BTypeEnum;
import com.logic.landseaserver.common.enums.BillTypeEnum;
import com.logic.landseaserver.common.enums.ContractStatusCodeEnum;
import com.logic.landseaserver.common.enums.LeaseCodeEnum;
import com.logic.landseaserver.common.enums.ProjectStatusCodeEnum;
import com.logic.landseaserver.common.enums.RoomStatusCodeEnum;
import com.logic.landseaserver.common.exception.LandseaBusinessException;
import com.logic.landseaserver.common.exception.LandseaException;
import com.logic.landseaserver.common.exception.ResultCodes.ChangeRoomResultCode;
import com.logic.landseaserver.common.exception.ResultCodes.PaymentResultCode;
import com.logic.landseaserver.common.util.ConstantChar;
import com.logic.landseaserver.common.util.LandSeaUtil;
import com.logic.landseaserver.common.util.StringTools;
import com.logic.landseaserver.models.authcode.service.CouponUsedService;
import com.logic.landseaserver.models.changeroom.bean.ChangeRoomContract;
import com.logic.landseaserver.models.changeroom.bean.ChangeRoomOffrentConfirm;
import com.logic.landseaserver.models.changeroom.bean.ChangeRoomReq;
import com.logic.landseaserver.models.independent.service.BillIndependentService;
import com.logic.landseaserver.models.prepayment.bean.AddAccountObject;
import com.logic.landseaserver.models.prepayment.service.PrepaymentService;
import com.logic.landseaserver.ws.dto.ContractDTO;
import com.logic.landseaserver.ws.dto.OffrentConfirmDTO;
import com.logic.landseaserver.ws.dto.ProjectDetailDTO;
import com.logic.landseaserver.ws.dto.QueryCouponUesdDTO;
import com.logic.landseaserver.ws.request.ContractNeedDelReq;
import com.logic.landseaserver.ws.request.CreateOffLineContractsReq;
import com.logic.landseaserver.ws.request.RoomDetailReq;
import com.logic.system.domain.SystemFile;
import com.logic.system.service.IConfigurationService;
import com.logic.system.service.IFileService;

/**
 *
 * 项目名称：system-server</br>
 * 类名称：ChangeRoomService</br>
 * 类描述：</br>
 * 创建人：Aaron</br>
 * 创建时间：2017年12月13日 下午1:52:31</br>
 * 
 * @version 1.0
 *
 */
@Service
public class ChangeRoomService
{
    private static final Logger LOGGER = LoggerFactory.getLogger(ChangeRoomService.class);
    
    @Autowired
    private ContractReadMapper contractReadMapper;
    
    @Autowired
    private ICustomer customerService;
    
    @Autowired
    private IProjectAppartment roomService;
    
    @Autowired
    private IContractOfflineService contractOfflineService;
    
    @Autowired
    private CouponUsedService couponUsedService;
    
    @Autowired
    private ContractWriteMapper contractWriteMapper;
    
    @Autowired
    private IBillService billService;
    
    @Autowired
    private IContractService contractService;
    
    @Autowired
    private ChangeRoomRecordWriteMapper changeRoomRecordWriteMapper;
    
    @Autowired
    private ChangeRoomRecordReadMapper changeRoomRecordReadMapper;
    
    @Autowired
    private CheckListWriteMapper checkListWriteMapper;
    
    @Autowired
    private CheckFeeListWriteMapper checkFeeListWriteMapper;
    
    @Autowired
    private IOffrentPreBill offrentPreBillService;
    
    @Autowired
    private ProjectReadMapper projectReadMapper;
    
    @Autowired
    private IOffRent offRentService;
    
    @Autowired
    private BillWriteMapper billWriteMapper;
    
    @Autowired
    private BillDetailWriteMapper billDetailWriteMapper;
    
    @Autowired
    private ChangeRoomPreBillService changeRoomPreBillService;
    
    @Autowired
    private OffrentConfirmReadMapper offrentConfirmReadMapper;
    
    @Autowired
    private OffrentConfirmWriteMapper offrentConfirmWriteMapper;
    
    @Autowired
    private IFileService fileService;
    
    @Autowired
    private PrepaymentService prepaymentService;
    
    @Autowired
    private RoomWriteMapper roomWriteMapper;
    
    @Autowired
    private BillIndependentService billIndependentService;
    
    @Autowired
    private RoomReadMapper roomReadMapper;

    @Autowired
    private UrgentWriteMapper urgentWriteMapper;
    
    @Autowired
    private BillReadMapper billReadMapper;
    
    @Autowired
    private BalanceSheetRecordWriteMapper balanceSheetRecordWriteMapper;
    
    @Autowired
    private IConfigurationService configurationService;

    @Autowired
    private CustomerCardWriteMapper customerCardWriteMapper;

    @Autowired
    private CustomerCardReadMapper customerCardReadMapper;

    @Autowired
    private IConfigurationQiyuesuoService configurationQiyuesuoService;

    
    /**
     * 
     * [简要描述]：创建换房信息</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2017-12-13)</br>
     *
     * @param request
     * @throws LandseaException
     * @throws LandseaBusinessException
     *
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {LandseaException.class, Exception.class})
    public Map<String, Object> createChangeRoom(ChangeRoomReq request)
        throws LandseaException, LandseaBusinessException
    {
        LOGGER.info("创建换房记录开始." + request.toString());
        
        Map<String, Object> resultMap = new HashMap<String, Object>();
        
        try
        {
            Integer systemId = SecurityUtils.getCurrentLogin().getUserId();
            if (systemId == null)
            {
                throw LandseaException.createException(LandseaErrorMessageEnum.TOKEN_IS_NULL);
            }
            
            if (request.getIsSameProject() == null)
            {
                throw LandseaException.createException(LandseaErrorMessageEnum.CHANGEROOM_ISSAMEPROJECT_ISNULL);
            }
            
            Integer oldContractId = request.getContractId();
            
            // 取当前合同
            Contract contract = contractReadMapper.selectByPrimaryKey(oldContractId);
            if (null == contract)
            {
                throw LandseaException.createException(PaymentResultCode.E00150011);
            }
            
            // 如果是跨店换房，不新增合同，只新增换房记录
            if (!request.getIsSameProject())
            {
                return notSameProjectChangeProcess(request, contract, systemId);
            }
            
            validateForInsert(request);
            
            // 获取当前用户版本
            Integer userId = request.getUserId();
            CustomerVersion customer = customerService.getNewVersion(userId);
            String version = customer == null ? "" : customer.getVersionNumber();
            // 这里的房间是要换入的房间
            RoomDetailReq roomDetailReq = roomService.searchRoomInfo(request.getDestRoomId());
            if (roomDetailReq == null)
            {
                throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_APRT_ISNULL);
            }
            
            // 校验房间
            checkRoomStatus(roomDetailReq, request);
            
            Integer month = 0;
            if (!contract.getLease().equals(LeaseCodeEnum.LEAS99.getCode()))
            {
                month = LeaseCodeEnum.getMonth(contract.getLease());
                contract.setLeaseM(month);
                contract.setLeaseD(0);
            }
            else
            {
                month = contract.getLeaseM();
            }
            
            // 合同算钱
            contractOfflineService.calculationMonthRent(roomDetailReq, request, month);
            LOGGER.info("创建换房合同->计算合同金额");
            
            // 新建合同,此时的合同的delete状态，防止被看到，在原始合同生成退房账单后打开
            Contract ctc = CreateOffLineContractsReq.convertDTOtoContract(request);
            ctc.setOutDate(contract.getOutDate());
            ctc.setUserId(userId);
            // 换入的房间信息及门店信息
            ctc.setProjectId(request.getDestProjectId());
            ctc.setRoomId(request.getDestRoomId());
            ctc.setOffLine(true);
            ctc.setUserVersion(version);
            ctc.setOriginalWaterDeposit(contract.getOriginalWaterDeposit());
            ctc.setRentType(LandeaConstants.ReRentType.TURN);
            ctc.setSourceRentType(LandeaConstants.ReRentType.TURN);
            ctc.setOriginalCId(request.getContractId());
            ctc.setSource(contract.getSource());
            ctc.updateCommonInfo(systemId);
            
            // 修改房间设置为已签约
            Room room = new Room();
            room.setId(request.getDestRoomId());
            room.setSigned(true);
            room.updateCommonInfo(systemId);
            //room.setAppendStatus(RoomStatusCodeEnum.LRB3.getCode());
            roomWriteMapper.updateByPrimaryKeySelective(room);
            
            // 查看是否有授权码
            couponUsedService.checkUesdAuthCode(LandeaConstants.QueryUesdCodeType.CONTRACT,
                userId,
                request.getAuthCodes());
            
            // 设置收取滞纳金、门锁时长
            Integer lateFeeDay = configurationService.getIntegerValue("SYS_TIM_FOR_LAT_FEE");
            Integer payLastDay = configurationService.getIntegerValue("PAY_LAST_DAY_TIME");
            ctc.setLatefeeDay(lateFeeDay);
            ctc.setLastPayDay(payLastDay);
            
            contractWriteMapper.insertSelective(ctc);
            Integer destContractId = ctc.getId();
            LOGGER.info("创建换房合同->入库换房合同完毕contractId=" + destContractId);
            
            if (null == destContractId)
            {
                LOGGER.error("创建换房合同->换房合同入库失败，入库后contractId为空.");
                throw LandseaException.createException(ChangeRoomResultCode.E010500001);
            }

            //新增紧急联系人
            if(customer.getEmergContact()!=null && customer.getEmergTel()!=null){
                Urgent urgent = new Urgent();
                urgent.setUrgentName(customer.getEmergContact());
                urgent.setUrgentPhone(customer.getEmergTel());
                urgent.setContractId(destContractId);
                urgent.setUrgentRelation(customer.getEmergRelation());
                urgent.updateCommonInfo(systemId);
                urgentWriteMapper.insertSelective(urgent);
            }
            //添加银行卡信息
            if(request.getCardUserName()!=null){
                CustomerCard customerCard =CreateOffLineContractsReq.convertDTOtoCustomerCard(request);
                customerCard.setSourceId(ctc.getId());
                customerCard.updateCommonInfo(systemId);
                customerCardWriteMapper.insertSelective(customerCard);
            }
            // 修改原始合同
            Contract oldContractUpdate = new Contract();
            oldContractUpdate.setId(oldContractId);
            oldContractUpdate.setRentType(LandeaConstants.ReRentType.TURN);
            oldContractUpdate.updateCommonInfo(systemId);
            contractWriteMapper.updateByPrimaryKeySelective(oldContractUpdate);
            LOGGER.info("创建换房记录->更新原始合同完毕.");
            
            // 入库换房记录表, userId + contractId 可确定唯一一条记录
            // 防止重复，先删除一遍
            ChangeRoomRecord deleteRecord = new ChangeRoomRecord();
            deleteRecord.setContractId(oldContractId);
            deleteRecord.setUserId(request.getUserId());
            deleteRecord.editInitCommonField();
            changeRoomRecordWriteMapper.deleteByUserAndConract(deleteRecord);
            
            ChangeRoomRecord changeRoomRecord = new ChangeRoomRecord();
            changeRoomRecord.setWid(StringTools.generateUuid());
            changeRoomRecord.setChangeDate(request.getChangeRoomDate());
            changeRoomRecord.setContractId(oldContractId);
            changeRoomRecord.setRoomId(contract.getRoomId());
            changeRoomRecord.setProjectId(contract.getProjectId());
            changeRoomRecord.setIsSameProject(request.getIsSameProject());
            changeRoomRecord.setDestProjectId(request.getDestProjectId());
            changeRoomRecord.setUserId(request.getUserId());
            // 状态为已生成换房合同
            changeRoomRecord.setStatus(ChangeRoomStatus.CREATE_CONTRACT);
            
            // 店内换房是有房间和项目的
            if (request.getIsSameProject())
            {
                changeRoomRecord.setDestRoomId(request.getDestRoomId());
            }
            
            changeRoomRecord.setReasonType(request.getReasonType());
            changeRoomRecord.setReasonDetail(request.getReasonDetail());
            changeRoomRecord.initCommonFieldWithUser(systemId);
            changeRoomRecordWriteMapper.insertSelective(changeRoomRecord);
            LOGGER.info("创建换房合同->新增换房记录表完毕,changeRoomId=" + changeRoomRecord.getId());
            
            // 创建首期账单
            billService.createFirstBill4ChangeRoom(ctc, request.getAuthCodes());
            LOGGER.info("创建换房合同->生成首期账单完毕.");
            
            resultMap.put("changeRoomId", changeRoomRecord.getId());
            resultMap.put("destContractId", destContractId);
            return resultMap;
        }
        catch (LandseaException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            LOGGER.error("创建换房信息失败.", e);
            throw LandseaException.createException(ChangeRoomResultCode.E010500001, e);
        }
    }
    
    /**
     * 
     * [简要描述]：跨店换房处理</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2017-12-14)</br>
     *
     */
    public Map<String, Object> notSameProjectChangeProcess(ChangeRoomReq request, Contract contract, Integer systemId)
    {
        Map<String, Object> resultMap = new HashMap<String, Object>();
        
        Integer oldContractId = contract.getId();
        
        // 修改原始合同
        Contract oldContractUpdate = new Contract();
        oldContractUpdate.setId(oldContractId);
        oldContractUpdate.setRentType(LandeaConstants.ReRentType.TURN);
        oldContractUpdate.updateCommonInfo(systemId);
        contractWriteMapper.updateByPrimaryKeySelective(oldContractUpdate);
        LOGGER.info("创建跨店换房记录->更新原始合同完毕.");
        
        // 入库换房记录表, userId + contractId 可确定唯一一条记录
        // 防止重复，先删除一遍
        ChangeRoomRecord deleteRecord = new ChangeRoomRecord();
        deleteRecord.setContractId(oldContractId);
        deleteRecord.setUserId(request.getUserId());
        changeRoomRecordWriteMapper.deleteByUserAndConract(deleteRecord);
        
        ChangeRoomRecord changeRoomRecord = new ChangeRoomRecord();
        changeRoomRecord.setWid(StringTools.generateUuid());
        changeRoomRecord.setChangeDate(new Date());
        changeRoomRecord.setContractId(oldContractId);
        changeRoomRecord.setRoomId(contract.getRoomId());
        changeRoomRecord.setProjectId(contract.getProjectId());
        changeRoomRecord.setIsSameProject(request.getIsSameProject());
        changeRoomRecord.setDestProjectId(request.getDestProjectId());
        changeRoomRecord.setUserId(request.getUserId());
        // 状态为未处理
        changeRoomRecord.setStatus(ChangeRoomStatus.NONE_PROCESS);
        
        // 店内换房是有房间和项目的
        if (request.getIsSameProject())
        {
            changeRoomRecord.setDestRoomId(request.getRoomId());
        }
        
        changeRoomRecord.setReasonType(request.getReasonType());
        changeRoomRecord.setReasonDetail(request.getReasonDetail());
        changeRoomRecord.initCommonFieldWithUser(systemId);
        changeRoomRecordWriteMapper.insertSelective(changeRoomRecord);
        LOGGER.info("创建跨店换房合同->新增换房记录表完毕,changeRoomId=" + changeRoomRecord.getId());
        
        resultMap.put("changeRoomId", changeRoomRecord.getId());
        return resultMap;
    }
    
    private void validateForInsert(ChangeRoomReq req)
        throws LandseaException
    {
        if (req.getReasonType() == null)
        {
            throw LandseaException.createException(LandseaErrorMessageEnum.CHANGEROOM_REASONTYPE_ISNULL);
        }
        
        if (req.getContractId() == null)
        {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_UPDATE_CONTRACTID_ISNULL);
        }
        if (req.getUserId() == null)
        {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_USERID_ISNULL);
        }
        if (req.getProjectId() == null)
        {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_PROJECTID_ISNULL);
        }
        
        if (req.getRoomId() == null)
        {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_ROOMID_ISNULL);
        }
        
        if (StringUtils.isEmpty(req.getPaymentMode()))
        {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_PAYMENTMODE_ISNULL);
        }
        
        if (StringUtils.isEmpty(req.getLease()))
        {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_LEASE_ISNULL);
        }
        
        if (req.getInDate() == null)
        {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_INDATE_ISNULL);
        }
        
        if (req.getOutDate() == null)
        {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_OUTDATE_ISNULL);
        }
        // 如果租期为其他 leaseM leaseD 不能为空
        if (req.getLease().equals(LeaseCodeEnum.LEAS99.getCode()))
        {
            if (req.getLeaseM() == null || req.getLeaseD() == null)
            {
                throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_LEASEMD_INDATE_INVALID);
            }
        }
    }
    
    /**
     * 
     * [简要描述]：查询换房合同</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2017-12-13)</br>
     *
     * @param contractId 原始合同ID
     * @return
     * @throws LandseaException
     *
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public ChangeRoomContract queryChangeRoom(Integer contractId)
        throws LandseaException
    {
        try
        {
            Contract contract = contractReadMapper.selectByPrimaryKey(contractId);
            if (null == contract)
            {
                return null;
            }
            
            ChangeRoomContract changeRoomContract = null;
            
            // 查询换房信息
            ChangeRoomRecord changeRoomRecord = new ChangeRoomRecord();
            changeRoomRecord.setUserId(contract.getUserId());
            changeRoomRecord.setContractId(contractId);
            changeRoomRecord = changeRoomRecordReadMapper.selectByUserAndContract(changeRoomRecord);
            
            if (null == changeRoomRecord)
            {
                return null;
            }
            
            Map<String, Object> paramMap = new HashMap<String, Object>();
            paramMap.put("contractId", contractId);
            paramMap.put("rentType", ReRentType.TURN);
            ContractDTO contractDTO = contractReadMapper.queryChangeRoomContractDetail(paramMap);
            if (contractDTO == null)
            {
                changeRoomContract = new ChangeRoomContract();
            }
            else
            {
                changeRoomContract = convertChangeRoom(contractDTO);
                // 查询授权码使用信息
                HashMap map = new HashMap();
                map.put("mainId", contractDTO.getId());
                map.put("mainType", LandeaConstants.QueryUesdCodeType.CONTRACT);
                List<QueryCouponUesdDTO> codes = couponUsedService.querypPersonalCouponList(map);
                changeRoomContract.setAuthCodes(codes);
                //查询银行卡信息
                changeRoomContract.setCustomerCardDTO(customerCardReadMapper.queryCardInfo(map));
            }
            
            if (null != changeRoomRecord)
            {
                changeRoomContract.setIsSameProject(changeRoomRecord.getIsSameProject());
                changeRoomContract.setReasonType(changeRoomRecord.getReasonType());
                changeRoomContract.setReasonDetail(changeRoomRecord.getReasonDetail());
                changeRoomContract.setChangeRoomDate(changeRoomRecord.getChangeDate());
                changeRoomContract.setDestProjectId(changeRoomRecord.getDestProjectId());
                changeRoomContract.setDestRoomId(changeRoomRecord.getDestRoomId());
                Project project = projectReadMapper.selectByPrimaryKey(changeRoomRecord.getDestProjectId());
                if (null != project)
                {
                    changeRoomContract.setDestProjectName(project.getPrjName());
                }
            }
            return changeRoomContract;
        }
        catch (Exception e)
        {
            LOGGER.error("查询换房信息失败.", e);
            throw LandseaException.createException(ChangeRoomResultCode.E010500002, e);
        }
    }
    
    private ChangeRoomContract convertChangeRoom(ContractDTO contractDTO)
    {
        Gson gson = new Gson();
        String objectStr = gson.toJson(contractDTO);
        ChangeRoomContract changeRoomContract = gson.fromJson(objectStr, ChangeRoomContract.class);
        return changeRoomContract;
    }
    
    /**
     * 
     * [简要描述]：取消换房</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2017-12-14)</br>
     *
     * @param contractId
     * @throws LandseaException
     *
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {LandseaException.class, Exception.class})
    public void cancelChangeRoom(Integer contractId)
        throws LandseaException
    {
        try
        {
            LOGGER.info("cancelChangeRoom|取消换房contractId=" + contractId);
            
            Contract contract = contractReadMapper.selectByPrimaryKey(contractId);
            if (contract == null)
            {
                LOGGER.error("cancelChangeRoom|取消换房contractId=" + contractId + "合同不存在");
                throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_IS_NULL);
            }
         
            // 是否可以取消只关心B合同是否签字，B合同没签字就可以取消
            Map<String, Object> paramMap = new HashMap<String, Object>();
            paramMap.put("contractId", contractId);
            paramMap.put("rentType", ReRentType.TURN);
            ContractDTO changeRoomContract = contractReadMapper.queryChangeRoomContractDetail(paramMap);
            
            boolean isHaveBContract = false;
            // B合同已经签字不能取消
            if (changeRoomContract != null)
            {
                if (changeRoomContract.getIsChapter())
                {
                    LOGGER.error("cancelChangeRoom|取消换房contractId=" + contractId + ",B合同已经签字不能取消");
                    throw LandseaException.createException(LandseaErrorMessageEnum.CHANGE_ROOM_IS_CHAPTER);
                }
                isHaveBContract = true;
            }
            
            Integer userId = contract.getUserId();
            
            // 查询换房记录
            ChangeRoomRecord changeRoomRecord = new ChangeRoomRecord();
            changeRoomRecord.setUserId(userId);
            changeRoomRecord.setContractId(contractId);
            changeRoomRecord = changeRoomRecordReadMapper.selectByUserAndContract(changeRoomRecord);
            
            if (null == changeRoomRecord)
            {
                LOGGER.info("cancelChangeRoom|无换房记录.contractId=" + contractId);
                return;
            }
            
            // 删除换房记录
            ChangeRoomRecord deleteRecord = new ChangeRoomRecord();
            deleteRecord.setContractId(contractId);
            deleteRecord.setUserId(userId);
            deleteRecord.editInitCommonField();
            changeRoomRecordWriteMapper.deleteByUserAndConract(deleteRecord);
            
            // 撤销退房交割单
            checkListWriteMapper.cancelCheckList(contractId, LandeaConstants.CheckType.UN_RENT);
            checkFeeListWriteMapper.cancelCheckFeeList(contractId, LandeaConstants.CheckType.UN_RENT);
            
            // 撤销预结算单
            offrentPreBillService.cancelPreBill(contractId);
            
            // 撤销预结算单的授权码使用记录
            PreOffrentBill preOffrentBill = offrentPreBillService.queryPreBillByContractId(contractId);
            if (preOffrentBill != null)
            {
                couponUsedService.deleteCouponUesd(preOffrentBill.getId(), LandeaConstants.QueryUesdCodeType.OFFRENT);
                // 撤销退房确认
                offrentConfirmWriteMapper.deleteByContractIdPreId(contractId, preOffrentBill.getId());
            }
            
            // 删除A合同的退房账单
            if (contract.getStatus().equals(ContractStatusCodeEnum.END.getCode()))
            {
                // 撤销退房账单
                Bill offBill = billReadMapper.queryOffrentBillByContract(contractId);
                if (offBill != null)
                {
                    billWriteMapper.deleteBillById(offBill.getId());
                    billDetailWriteMapper.deleteByBillId(offBill.getId());
                    // 删除独立账单
                    Map<String, Object> paramMapT = new HashMap<String, Object>();
                    paramMapT.put("contractId", contractId);
                    paramMapT.put("billId", offBill.getId());
                    paramMapT.put("billType", BTypeEnum._BT2.getCode());
                    balanceSheetRecordWriteMapper.removeFirstBillBalance(paramMapT);
                }
            }

            
            //恢复A合同
            contractWriteMapper.updateRentTypeNull(contractId);
            // 恢复A合同的房间状态
            // 恢复A合同的房间在住房间
            Room roomA = new Room();
            roomA.setId(contract.getRoomId());
            roomA.setAppendStatus(RoomStatusCodeEnum.LRB3.getCode());
            roomA.setSigned(true);
            roomA.setDirtyFlag(false);
            roomA.setOffrentStatus(false);
            roomWriteMapper.updateByPrimaryKeySelective(roomA);
            
            if (isHaveBContract)
            {
                // 撤销B合同
                // 删除续租B合同
                List<ContractNeedDelReq> contractList = new ArrayList<ContractNeedDelReq>();
                ContractNeedDelReq req = new ContractNeedDelReq();
                req.setRoomId(contract.getRoomId());
                req.setId(changeRoomContract.getId());
                contractList.add(req);
                // 删除账单
                billService.deleteNoPayBill(contractList);
                // 删除合同
                contractService.deleteNoPayContracts(contractList);
                // 根据合同删除独立账单
                contractService.deleteBalanceByContract(contractList);
                // 删除授权码使用记录
                couponUsedService.deleteCouponUesd(changeRoomContract.getId(),
                    LandeaConstants.QueryUesdCodeType.CONTRACT);
                
                // 释放房源
                Room room = new Room();
                room.setId(changeRoomRecord.getDestRoomId());
                room.setAppendStatus(RoomStatusCodeEnum.LRB1.getCode());
                room.setSigned(false);
                room.updateCommonInfo(SecurityUtils.getCurrentLogin().getUserId());
                roomWriteMapper.updateByPrimaryKeySelective(room);
            }
            
            // 清空原合同的rentType标记
            contractWriteMapper.updateRentTypeNull(contractId);
            
            // 还原A账户状态
            prepaymentService.updateAccountStatusByRoomAndUser(contract.getRoomId(), contract.getUserId(), AccountStatus.NORMAL);
        }
        catch (LandseaException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            LOGGER.error("查询换房信息失败.", e);
            throw LandseaException.createException(ChangeRoomResultCode.E010500003, e);
        }
    }
    
    /**
     * 
     * [简要描述]：</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2017-12-14)</br>
     *
     * @param contractId
     * @throws LandseaException
     *
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {LandseaException.class, Exception.class})
    public void createChangeRoomPreBill(Integer contractId)
        throws LandseaException
    {
        // 查询该合同是否存在
        Contract contract = contractReadMapper.selectByPrimaryKey(contractId);
        if (contract == null)
        {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_IS_NULL);
        }
        if (!org.apache.commons.lang.StringUtils.isEmpty(contract.getRentStatus()))
        {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_RENTTYPE_ERROR);
        }
        // 判断是否存在有效的预结算单，如存在则删除
        offrentPreBillService.deletePreBillByContractId(contract.getId());
        changeRoomPreBillService.createPreBill(contract);
        
        // 冻结账户状态
        prepaymentService.updateAccountStatusByRoomAndUser(contract.getRoomId(),contract.getUserId(), AccountStatus.CHANGE_ROOM);
    }
    
    /**
     * 换房B合同签过字要做的事情
     * @param contractId B合同ID
     * @throws LandseaException
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {LandseaException.class, Exception.class})
    public void synOverList(Integer contractId)
        throws LandseaException
    {
        Integer systemId = SecurityUtils.getCurrentLogin().getUserId();
        // 查询该合同是否存在
        Contract contract = contractReadMapper.selectByPrimaryKey(contractId);
        if (contract == null)
        {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_IS_NULL);
        }
        if (contract.getOriginalCId() != null && contract.getRentType() != null)
        {
            // 如果是换房合同
            if (contract.getRentType().equals(ReRentType.TURN))
            {
                // 获取A合同
                Contract contractA = contractReadMapper.selectByPrimaryKey(contract.getOriginalCId());
                if (contractA == null)
                {
                    throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_IS_NULL);
                }
                // 判断是否项目内换房
                ChangeRoomRecord crr = new ChangeRoomRecord();
                crr.setUserId(contractA.getUserId());
                crr.setContractId(contractA.getId());
                ChangeRoomRecord changeRoomRecord = changeRoomRecordReadMapper.selectByUserAndContract(crr);
                if (changeRoomRecord == null)
                {
                    throw LandseaException.createException(LandseaErrorMessageEnum.CHANGEROOM_RECORD_IS_NOTEXIST);
                }
                PreOffrentBill preBill = offrentPreBillService.queryPreBillByContractId(contractA.getId());
                if (preBill == null)
                {
                    throw LandseaException.createException(LandseaErrorMessageEnum.OFFRENT_PRE_BILL_ERROR);
                }
                
                // 更新换房信息表状态为换房结束
                ChangeRoomRecord changeRoomRecordUpdate = new ChangeRoomRecord();
                changeRoomRecordUpdate.setUserId(contractA.getUserId());
                changeRoomRecordUpdate.setContractId(contractA.getId());
                changeRoomRecordUpdate.setStatus(ChangeRoomStatus.SUCCESS);
                changeRoomRecordWriteMapper.updateByPrimaryKeySelective(changeRoomRecord);
                LOGGER.info("synOverList|更新换房信息表状态为换房结束完毕.userId=" + contractA.getUserId() + ",contractId=" + contractA.getId());
                
                // 退房/结转单金额大于0 应收租客钱放B换房首期款
                if (preBill.getRefundAmount() >= 0.0)
                {
                    // 非项目内换房
                    if (!changeRoomRecord.getIsSameProject())
                    {
                        // 生成原合同退房账单
                        offRentService.createOffRentBill(contract.getOriginalCId());
                    }
                    // 将A账单结转到B的“其他”费项
                    if (preBill.getRefundAmount() != 0.0)
                    {
                        Bill parBil = billService.queryFirstBill(contractId);
                        parBil.setReceivableMoney(
                            LandSeaUtil.get2Double(parBil.getReceivableMoney() + preBill.getRefundAmount()));
                        parBil.updateCommonInfo(systemId);
                        billWriteMapper.updateByPrimaryKeySelective(parBil);
                        
                        BillDetail billDetail = new BillDetail();
                        billDetail.setBillId(parBil.getId());
                        billDetail.setDateBegin(new Date());
                        billDetail.setDateEnd(new Date());
                        billDetail.setType(BillTypeEnum.CTBI12.getCode());
                        billDetail.setMoney(preBill.getRefundAmount());
                        billDetail.setRemark(contractA.getContractNo() + ConstantChar.sys_contract_pay);
                        billDetail.setOverlistFlag(LandeaConstants.ReRentFlag.TURN);
                        billDetail.updateCommonInfo(systemId);
                        billDetailWriteMapper.insertSelective(billDetail);
                        
                        // 入库独立账单
                        BalanceSheetRecord balanceSheetRecord = billIndependentService.buildFirstBillBalanceRecord(contract, parBil, billDetail);
                        Room room = roomReadMapper.selectByPrimaryKey(contract.getRoomId());
                        if (null != room)
                        {
                            balanceSheetRecord.setHouseNum(room.getHouseNum());
                        }
                        balanceSheetRecord.setStartTime(contract.getInDate());
                        billIndependentService.insertBalanceSheet(balanceSheetRecord);
                    }
                }
                else
                {
                    // 非项目内换房
                    if (!changeRoomRecord.getIsSameProject())
                    {
                        // 生成原合同退房账单
                        offRentService.createOffRentBill(contract.getOriginalCId());
                    }
                    
                    // 需要把账单要退的钱转到自己的余额
                    prepaymentService.billMoney2AccountBalance(contractA);
                }
                
                // 创建B的账户
                AddAccountObject object = new AddAccountObject();
                object.setRoomId(contract.getRoomId());
                object.setProjectId(contract.getProjectId());
                object.setUserId(contract.getUserId());
                object.setContractId(contract.getId());
                prepaymentService.addAccount(object);
            }
        }
    }
    
    /**
     * 
     * [简要描述]：查询项目同属子公司的其他项目</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2017-12-15)</br>
     *
     * @param projectId
     *
     */
    public List<Project> changeRoomGetProject(Integer projectId)
        throws LandseaException
    {
        List<Project> resultList = new ArrayList<Project>();
        try
        {
            Project project = projectReadMapper.selectByPrimaryKey(projectId);
            if (null == project || project.getDeleted())
            {
                LOGGER.error("changeRoomGetProject|项目不存在projectId=" + projectId);
                return resultList;
            }

            ConfigurationQiyuesuo qiyuesuo = (ConfigurationQiyuesuo) configurationQiyuesuoService.get(projectId);
            List<Project> projectList = new ArrayList<>();
            if(qiyuesuo!=null){
                String sealId=String.valueOf(qiyuesuo.getSealId());
                // 根据该项目的城市公司查询所有正常的项目,项目为发布态、非删除态
                projectList = projectReadMapper.selectChangeRoomList(projectId,sealId);
            }
            return projectList;
        }
        catch (Exception e)
        {
            LOGGER.error("changeRoomGetProject|查询SQL错误.projectId=" + projectId, e);
            return resultList;
        }
    }
    
    /**
     * 
     * [简要描述]：合同列表查询待换房的数量</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2017-12-18)</br>
     *
     * @param paramMap
     * @return
     *
     */
    public Map<String, Object> getChangeRoomCount(Map<String, Object> paramMap)
    {
        Map<String, Object> result = new HashMap<String, Object>();
        try
        {
            Map<String, Object> queryMap = new HashMap<String, Object>();
            Integer userId = SecurityUtils.getCurrentLogin().getUserId();
            String prjIdStr = StringTools.getString(paramMap.get("prjId"));
            Integer prjId = null;
            if (StringUtils.isNotEmpty(prjIdStr))
            {
                prjId = Integer.parseInt(prjIdStr);
            }
            queryMap.put("projectId", prjId);
            queryMap.put("userId", userId);
            Integer totalCount = contractReadMapper.getChangeRoomCount(paramMap);
            if (null == totalCount)
            {
                result.put("count", 0);
            }
            else
            {
                result.put("count", totalCount);
            }
        }
        catch (Exception e)
        {
            LOGGER.error("getChangeRoomCount|查询换房数量失败.paramMap=" + paramMap, e);
        }
        
        return result;
    }
    
    /**
     * 
     * [简要描述]：确认换房</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2017-12-18)</br>
     *
     * @param offrentConfirm
     * @throws LandseaException
     *
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {LandseaException.class, Exception.class})
    public void confirmChangeRoom(ChangeRoomOffrentConfirm offrentConfirm)
        throws LandseaException
    {
        try
        {
            if (null == offrentConfirm.getContractEndDate())
            {
                offrentConfirm.setContractEndDate(new Date());
            }
            
            if (null == offrentConfirm.getContractId())
            {
                throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACTID_IS_NULL);
            }
            if (null == offrentConfirm.getFileId())
            {
                throw LandseaException.createException(LandseaErrorMessageEnum.FILEID_IS_NULL);
            }
            if (null == offrentConfirm.getPreBillId())
            {
                throw LandseaException.createException(LandseaErrorMessageEnum.PREBILLID_IS_NULL);
            }
            
            OffrentConfirm oc = offrentConfirmReadMapper.selectByContractId(offrentConfirm.getContractId());
            
            if (null == oc)
            {
                offrentConfirm.setId(null);
                offrentConfirmWriteMapper.insertSelectiveOffrentConfirm(offrentConfirm);
            }
            else
            {
                offrentConfirmWriteMapper.updateByContractIdAndPrebillIdSelective(offrentConfirm);
            }
            
            Contract contract = new Contract();
            contract.setId(offrentConfirm.getContractId());
            contract.setRentStatus(LandeaConstants.ReRentType.TURN);
            contract.updateCommonInfo(SecurityUtils.getCurrentLogin().getUserId());
            contractWriteMapper.updateByPrimaryKeySelective(contract);
        }
        catch (LandseaException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            LOGGER.error("confirmChangeRoom|确认换房失败.", e);
            throw LandseaException.createException(LandseaErrorMessageEnum.CONFIRM_CHANGE_ROOM_ERROR, e);
        }
    }
    
    /**
     * 
     * [简要描述]：查询换房确认单</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2017-12-18)</br>
     *
     * @param contractId
     * @return
     * @throws BusinessException
     * @throws LandseaException 
     *
     */
    public OffrentConfirmDTO getConfirmChangeRoom(Integer contractId)
        throws BusinessException, LandseaException
    {
        try
        {
            OffrentConfirmDTO dto = new OffrentConfirmDTO();
            List<SystemFile> filelist = new ArrayList<SystemFile>();
            OffrentConfirm oc = offrentConfirmReadMapper.selectByContractId(contractId);
            if (null != oc)
            {
                String fileIds = oc.getFileId();
                if (fileIds != null)
                {
                    String[] fileidarray = fileIds.split(",");
                    for (String id : fileidarray)
                    {
                        SystemFile systemFile = (SystemFile)fileService.get(id);
                        filelist.add(systemFile);
                    }
                }
            }
            dto.setOffrentConfirm(oc);
            dto.setFileList(filelist);
            
            return dto;
        }
        catch (BusinessException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            LOGGER.error("getConfirmChangeRoom|查询换房确认失败.", e);
            throw LandseaException.createException(LandseaErrorMessageEnum.QUERY_CONFIRM_CHANGE_ROOM_ERROR, e);
        }
    }
    
    /**
     * 
     * [简要描述]：检查房间</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2017-12-19)</br>
     *
     * @param aprt
     * @param objCts
     * @throws LandseaException
     *
     */
    private void checkRoomStatus(RoomDetailReq aprt, CreateOffLineContractsReq objCts)
        throws LandseaException
    {
        ProjectDetailDTO project = aprt.getProject();
        if (project == null)
        {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_PROJECT_ISNULL);
        }
        
        if (!project.getStatus().equals(ProjectStatusCodeEnum.LPA2.getCode()))
        {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_PROJECT_IS_LPA2);
        }
        
        if (!aprt.getStatus().equals(RoomStatusCodeEnum.LRA2.getCode()))
        {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_ROOM_IS_LPA2);
        }
        if (!aprt.getAppendStatus().equals(RoomStatusCodeEnum.LRB1.getCode())
            && !aprt.getAppendStatus().equals(RoomStatusCodeEnum.LRB2.getCode()))
        {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_ROOM_IS_LPB1);
        }
        
        // 判断是否支持此付租方式
        List<String> list = Arrays.asList(project.getPaymentMode().split(","));
        if (!list.contains(objCts.getPaymentMode()))
        {
            throw LandseaException.createException(
                LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_PROJECT_HAS_NO_PAYMENTHOD_MODEL);
        }
        // 判断是否支持此租期
        List<String> list2 = Arrays.asList(project.getLease().split(","));
        if (!list2.contains(objCts.getLease()))
        {
            throw LandseaException.createException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_PROJECT_HAS_NO_LEASE);
        }
    }

    public void clearOverTimeCRRecord(String changeDate){
        List<Contract> cancleChanges = contractReadMapper.queryCancleChaneRoom(changeDate);
        if(cancleChanges.size()>0){
            for(Contract ct:cancleChanges){
                try {
                    cancelChangeRoom(ct.getId());
                    LOGGER.info("clearOverTimeChangeRoomRecord contractId is :"+ ct.getId());
                } catch (LandseaException e) {
                    LOGGER.error("clearOverTimeChangeRoomRecordis error",e.getMessage());
                }
            }
        }
    }
}
